import {replaceByObj,ifNull,addClass,removeClass} from './xUtil.js';
import xID from "./xID.js";

/*
  cfg:{
    data:{code,name}
    placeholer:'',
    style:
  }
 */
const tmplBase = `<div class="{{class}}" >
                     <div type="input-head" class="xhead">                                                             
                     </div>           
                  </div>`;
const tmplInput = '<input {{type}} {{key}} {{value}} {{name}} {{readonly}} {{placeholder}} {{title}} {{class}}/>';
const tmplCheck = '<label>{{input}}{{label}}</label>';
const tmplDiv = '<div type="{{type}}" {{title}}>{{html}}</div>';
const tmplSpanHtml = '<span type ="{{type}}">{{html}}</span>';
const tmplFileInput = '<input type="file" {{key}}  {{multiple}}  {{title}} />';
const tmplRate =`<span type="span-rate">
                     <i class="iconfont icon-f-star-left" type= "star" data-code="{{codeLeft}}"></i> 
                     <i class="iconfont icon-f-star-right" type = "star" data-code="{{codeRight}}"></i>
                  </span>`;
const tmplTextarea ='<textarea {{type}} {{rows}} {{placeholder}} {{title}} {{id}}></textarea>';

const tmplSwitch ='<div type ="switch" {{class}} {{title}}><span type="span-switch">{{html}}</span></div>';
const tmplIconCircle = '<i class="iconfont icon-f-circle"></i>';

const tmplTitle = `title="{{title}}"`;
const tmplRange = `<div type="range"><input type="range" min="{{min}}" max="{{max}}" step="{{step}}"
                      value="0"  {{title}}/><span type="range-value">0</span></div>`;

export default class xInput {
    /* 定义变量 开始*/
    // jquery 对象
    $root;
    $head;
    vBindEvent;
    vCfg;
    vInputValue;
    vInputName ;
    vTmpEvent ={};
    vClickId = 'click.'+xID.getID();
    /* 定义变量 结束*/

    constructor(cfg) {
        this.$root = $('#' + cfg.el);
        this.vInputValue = cfg.active;
        if(cfg.name)
            this.vInputName = cfg.name;
        else
            this.vInputName = xID.getID();
        this.$root.html(tmplBase.replace('{{class}}', cfg.style||'input'));
        this.vCfg = cfg;
        this.init();
    };

    /* 渲染区块 开始 */
    init() {
        this.$head = this.$root.find('[type="input-head"]');
        this.renderHead();
        this.renderStatus();
        //this.$head.on('click', this.evClick.bind(this));
        switch(this.vCfg.type){
            case 'switch':
                this.regSwitchEv();
                break;
            case 'radio':
            case 'checkbox':
            case 'text':
            case 'file':
            case 'password':
            case 'range':
            case 'color':
                this.regInputEv();
                break;
            case 'rate':
                this.regRateEv();
                break;
            case 'textarea':
                this.regTextareaEv();
                break;
            case 'modal':
                this.regModalEv();
                break;
        }

        this.$root.on('click', this.evRootClick.bind(this));
        this.$root.on('keydown',this.evKeydown.bind(this));
        this.$root.on('focus','input[type="text"]',this.evFocus.bind(this));

        if(this.vCfg.readonly)
            this.setReadonly(true);
    };

    renderStatus(action,status){
        if(action=='add'){
            this.$head.addClass(status);
        }else{
            this.$head.removeClass(status);
        }
    }

    initValue(value){
        if(this.vInputValue != value){
            this.vInputValue =value;
            switch(this.vCfg.type){
                case 'radio':
                    this.$head.find('input[name="'+this.vInputName+'"]').each((index,el) =>{
                        if(this.vInputValue==el.value)
                            el.checked = true;
                        else
                            el.checked= false;
                    });
                    break;
                case 'checkbox':
                    this.$head.find('input[name="'+this.vInputName+'"]').each((index,el) =>{
                        if(this.vInputValue.includes(el.value))
                            el.checked = true;
                        else
                            el.checked= false;
                    });
                    break;
                case 'rate':
                    this.$head.html(this.renderRate());
                    break;
                case 'switch':
                    this.$head.html(this.renderSwitch());
                    break;
                case 'text':
                case 'file':
                    this.$head.find('input').val(value||'');
                    break;
                case 'range':
                    this.$head.find('input').val(value||'');
                    this.$head.find('span[type="input-value"]').html(value||'');
                    break;
                case 'modal':
                    this.modalEcho(value);
                    break;
            }
            this.verify();
        }
    }

    renderHead(){
        let itemHtml;
        switch(this.vCfg.type){
            case 'radio':
                itemHtml = this.renderRadio();
                this.$head.html(itemHtml);
                break;
            case 'checkbox':
                itemHtml = this.renderCheck();
                this.$head.html(itemHtml);
                break;
            case 'text':
                itemHtml = this.renderText();
                this.$head.html(itemHtml);
                break;
            case 'file':
                this.$head.html(this.renderFile());
                break;
            case 'password':
                this.$head.html(this.renderPassword());
                break;
            case 'rate':
                this.$head.html(this.renderRate());
                break;
            case 'textarea':
                this.$head.html(this.renderTextarea());
                break;
            case 'switch':
                this.$head.html(this.renderSwitch())
                break;
            case 'modal':
                this.$head.html(this.renderModal());
                this.$head.addClass("input-modal");
                break;
            case 'range':
                this.$head.html(this.renderRange());
                //this.$head.find('span[type="range-value"]').html(this.vInputValue);
                break;
            case 'color':
                this.$head.html(this.renderColor());
                break;
        }

    }

    renderRadio(){
        let [html,inputHtml,value,label,title] =['','','','',''];
        let key ='key="input-radio"';
        let type ='type="radio"';
        let name ='name="'+this.vInputName+'" ';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        for(let o of this.vCfg.data){
            value = 'value="'+o.code+'"';
            label  = o.name||o.code;
            inputHtml = replaceByObj(tmplInput,{key,type,value ,name,placeholder:'',
                readonly:'',class:'class="form-check-input"'});
            html += replaceByObj(tmplCheck,{input:inputHtml,label});
        }
        return replaceByObj(tmplDiv,{type:"radio",html,title});
    }

    renderText(){
        let value ='',type ='type="text"',key ='';
        let name =' ',placeholder='',readonly ='', title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        if(this.vCfg.placeholder)
            placeholder = 'placeholder="'+this.vCfg.placeholder+'"'
        return replaceByObj(tmplInput,{type,key,name,value,placeholder,title,readonly,class:'class="xinput"'});
    }

    renderColor(){
        let key ='key="input-color"';
        let type ='type="color"';
        let title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        return replaceByObj(tmplInput,{type,type,name:'',value:'',placeholder:'',
            title,readonly:'',class:'class="xinput"'});
    }

    renderRange(){
        let [title,min,max,step] =['',this.vCfg.min||'0',this.vCfg.max||'100',this.vCfg.step||'0'];
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);

        return replaceByObj(tmplRange,{title,min,max,step});
    }

    renderFile(){
        let type ='type="input-file"';
        let title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        return replaceByObj(tmplFileInput,{type,multiple:this.vCfg.multiple?'multiple="multiple"':'',title});
    }

    renderPassword(){
        let value ='', type ='type="password"', key ='key="password"';
        let name =' ', title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        return replaceByObj(tmplInput,{type,key,name,value,placeholder:'',title,readonly:'',class:'class="xinput"'});
    }

    renderRate(){
        let html ='' ,val = ifNull(this.vInputValue,0)*2 ,title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        for(let i=1;i<6;i++){
            html += replaceByObj(tmplRate,{brightLeft:val>=i*2-1?'bright':'',
                codeLeft:i*2-1,brightRight:val>=i*2?'bright':'',codeRight:i*2});
        }
        return replaceByObj(tmplDiv,{type:"rate",html,title});
    }

    renderTextarea(){
        let type ='type="textarea"' ,placeholder='', rows ='',title ='',id='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        if(this.vCfg.placeholder)
            placeholder = 'placeholder="'+this.vCfg.placeholder+'"'
        if(this.vCfg.rows)
            rows = 'rows="'+this.vCfg.rows+'"';
        if(this.vCfg.id)
            id = 'id="'+this.vCfg.id+'"';

        return replaceByObj(tmplTextarea,{type,placeholder,rows,title,id});
    }

    renderSwitch(){

        let name = '' ,title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        if(this.vCfg.data)
            name= (this.vInputValue==1)? this.vCfg.data.split(',')[1]:this.vCfg.data.split(',')[0];
        let switchHtml =tmplIconCircle+ replaceByObj(tmplSpanHtml,{html:name,type:'switch-name'});
        return replaceByObj(tmplSwitch,{html:switchHtml,class:(this.vInputValue==1)?'class="checked"':'',title});
    }

    renderModal(){
        let value ='';
        let type ='type="modal"';
        let key ='';
        let name =' ';
        let placeholder='';
        let readonly ='readonly';
        let title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        if(this.vCfg.placeholder)
            placeholder = 'placeholder="'+this.vCfg.placeholder+'"'
        return replaceByObj(tmplInput,{type,key,name,value,placeholder,title,
            readonly,class:'class="xinput-icon"'});
    }

    regInputEv(){
        this.$head.on('input',this.evInput.bind(this));
    }

    regTextareaEv(){
        this.$head.on('change','[type="textarea"]',this.evChange.bind(this));
    }

    regModalEv(){
        this.$head.on('click',this.evModal.bind(this));
    }

    regSwitchEv(){
        this.$head.on('click', '[type="switch"]',this.evSwitchClick.bind(this));
    }

    regRateEv(){
        this.$head.on('mouseenter', '[type="star"]', this.evHoverIn.bind(this));
        //注意 这里 不需要 再加选择
        this.$head.on('mouseleave','[type="star"]', this.evHoverOut.bind(this));
        this.$head.on('mouseleave', this.evHeadHoverOut.bind(this));
        this.$head.on('click',  '[type="star"]',this.evStarClick.bind(this));
    }

    renderCheck(){
        let [html,inputHtml,value,label,title] =['','','','',''];
        let key ='key="input-checkbox"';
        let type ='type="checkbox"';
        let name ='name="'+this.vInputName+'" ';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        for(let o of this.vCfg.data){
            value = 'value="'+o.code+'"';
            label  = o.name||o.code;
            inputHtml = replaceByObj(tmplInput,{type,key,value ,name,placeholder:'',
                title:'',readonly:'',class:'class="form-check-input"'});
            html += replaceByObj(tmplCheck,{input:inputHtml,label});
        }
        return replaceByObj(tmplDiv,{type:"checkbox",html,title});

    }
    /*
    evClick(e){
        this.renderStatus("add","active");
        $(document).unbind(this.vClickId);
        $(document).on(this.vClickId,this.evOff.bind(this));
    }*/
    evKeydown(e){
        let keynum = window.event ? e.keyCode : e.which;
        switch(keynum){
            //tab 失去焦点
            case 9:
                switch(this.vCfg.type){
                    //如果是最后一个 才需要 off
                    case 'checkbox':
                        if(this.$root.find('input:last')[0] == document.activeElement)
                            this.evOff.bind(this)(e);
                        break;
                    default:
                        this.evOff.bind(this)(e);
                }

                break;
        }
    }

    evInput(e){
        let change =true;
        switch(this.vCfg.type){
            case 'radio':
            case 'checkbox':
                let val=[];
                this.$head.find('input[name="'+this.vInputName+'"]:checked').each((index,el) =>val.push(el.value));
                this.vInputValue = val.join(',');
                break;
            case 'text':
                if(this.vCfg.pattern){
                    let RegVal = e.target.value.replace(this.vCfg.pattern,'');
                    //没有被替换掉说明 不满足正则表达式 需要回退
                    if(RegVal == e.target.value && e.target.value && this.vCfg.inputVerify){
                        e.target.value= this.vInputValue;
                        change = false;
                    }else{
                        this.vInputValue = e.target.value;
                    }
                }else
                    this.vInputValue =  e.target.value;
                break;
            case 'password':
            case 'file':
            case 'color':
                this.vInputValue = e.target.value;
                break;
            case 'range':
                this.vInputValue = e.target.value;
                this.$head.find('span[type="range-value"]').html(this.vInputValue);
                break;
        }
        //this.renderStatus();
        if(change && this.vBindEvent)
            this.vBindEvent(this.vInputValue);
    }

    evFocus(e){
        this.renderStatus('add','active');
        $(document).unbind(this.vClickId);
        $(document).on(this.vClickId,this.evOff.bind(this));
    }

    evChange(e){
        let change =true;
        this.renderStatus();
        if(change && this.vBindEvent)
            this.vBindEvent(this.vInputValue);
        // textarea 自适应高度    
    }

    evHoverIn(e){
        if(this.vCfg.readonly)
            return;
        let code = e.target.getAttribute("data-code")-0;

        if(!this.vCfg.half)
            code = Math.round(code/2)*2;

        this.$head.find('[type="star"]').each((index,el) => {
            if(el.getAttribute("data-code")<= code)
                addClass(el,'bright');
        })
    }

    evHoverOut(e){
        if(this.vCfg.readonly)
            return;
        this.$head.find('[type="star"]').each((index,el) => {
            removeClass(el,'bright');
        })
    }

    evHeadHoverOut(e){
        let code = this.vInputValue*2;
        if(!this.vCfg.half)
            code = Math.round(code/2)*2;
        this.$head.find('[type="star"]').each((index,el) => {
            removeClass(el,'bright');
            if(el.getAttribute("data-code")<= code)
                addClass(el,'bright');
        })
    }

    evStarClick(e){
        if(this.vCfg.readonly)
            return;
        let code = e.target.getAttribute("data-code")-0;
        if(!this.vCfg.half)
            code = Math.round(code/2)*2;
        this.vInputValue=code/2;
        this.$head.find('[type="star"]').each((index,el) => {
            if(el.getAttribute("data-code")<= code)
                addClass(el,'bright');
        })

        if(this.vBindEvent)
            this.vBindEvent(this.vInputValue);
    }

    evSwitchClick(e){
        if(this.vCfg.readonly)
            return;
        this.vInputValue = this.vInputValue?0:1;
        let $comp = this.$head.find('[type="switch"]');
        let $name = this.$head.find('[type="switch-name"]');
        if(this.vInputValue){
            $comp.addClass("checked")
            $name.html(this.vCfg.data.split(',')[1])
        }else{
            $comp.removeClass("checked")
            $name.html(this.vCfg.data.split(',')[0])
        }
        this.renderStatus("active");
        if(this.vBindEvent)
            this.vBindEvent(this.vInputValue);
    }

    evModal(e){
        if(this.vCfg.readonly)
            return;
        if(this.vCfg.modal && this.vCfg.modal.show)
            this.vCfg.modal.show({data:this.vInputValue,
                confirm:this.cbModalConfirm.bind(this),
                cancle:this.cbModalCancle.bind(this)});
    }


    evRootClick(e){
        this.vTmpEvent.timeStamp = e.timeStamp;
        this.vTmpEvent.target =e .target;
        this.$root.find('input[type="text"]').focus();
    };

    evOff(e){
        if((e.type=='keydown') ||
                (e.type=='click' && (this.vTmpEvent.timeStamp !=e.timeStamp || this.vTmpEvent.target !=e.target))){
            this.renderStatus('remove','active');
            this.verify();
            $(document).unbind(this.vClickId);
        }

    }

   //模态框回显
    modalEcho(data){
        this.vInputValue =data;
        let val ='';
        if(data){
            let type = data instanceof Array?'Array': data instanceof Object?'Object':'';
            switch(type){
                case 'Array':
                    let i =[];
                    for(let v of data)
                        i.push(v.name||v.code||'');
                    val =i.join(',');
                    break;
                case 'Object':
                    val = this.vInputValue.name||this.vInputValue.code||'';
                    break;
            }
        }
        //let val = this.vInputValue?this.vInputValue.name||this.vInputValue.code||'':'';
        let $input  = this.$root.find('input');
        $input.val(val);
    }
    //模态框确认回调函数
    cbModalConfirm(data){
        this.modalEcho(data);
        this.renderStatus("active");
        this.$root.find('input').focus();
        if(this.vBindEvent)
            this.vBindEvent(this.vInputValue);
    }

    //模态框关闭回调函数
    cbModalCancle(){
        this.renderStatus("active");
        this.$root.find('input').focus();
    }

    setReadonly(status){
        this.vCfg.readonly = status;
        //console.log(status);
        if(status){
            this.renderStatus("add","readonly");
            //this.$input.attr("readonly","readonly")
            switch(this.vCfg.type){
                case 'checkbox':
                case 'radio':
                case 'text':
                case 'file':
                case 'password':
                case 'range':
                case 'color':
                    this.$head.find("input").each((index,el) =>
                    { $(el).attr("disabled","true") } );
                    break;
                case 'textarea':
                    this.$head.find("textarea").each((index,el) =>
                    { $(el).attr("disabled","true") } );
                    break;
            }
        }else{
            this.renderStatus("remove","readonly");
            switch(this.vCfg.type){
                case 'checkbox':
                case 'radio':
                case 'text':
                case 'file':
                case 'password':
                case 'range':
                case 'color':
                    this.$head.find("input").each((index,el) =>
                    { $(el).removeAttr("disabled") } );
                    break;
                case 'textarea':
                    this.$head.find("textarea").each((index,el) =>
                    { $(el).removeAttr("disabled") } );
                    break;
            }
        }
    }

    setBindEvent(event){
        this.vBindEvent = event;
    };

    setValue(value){
        this.initValue(value);
    };

    setData(data){
        this.vCfg.data =data;
        this.renderHead();
    }

    verify(){
        let result = true;
        let valid ;
        /*
        三种情况
        1 强制+正则
        2 强制无正则
        3 正则无强制
        4 无强制无正则
        * */
        if(this.vCfg.mandatory && this.vCfg.pattern){
            this.vCfg.pattern.lastIndex=0;
            if(!this.vCfg.pattern.test(this.vInputValue)){
                valid = -1;
                result = false;
            }
            else
                valid = 1 ;
        };


        if(!this.vCfg.mandatory && this.vCfg.pattern){
            this.vCfg.pattern.lastIndex=0;
            if(this.vInputValue){
                if(this.vCfg.pattern.test(this.vInputValue)){
                    valid =1;
                }else{
                    valid = -1 ;
                    result = false;
                }
            }else
                valid = 0;
        };

        if(this.vCfg.mandatory && !this.vCfg.pattern){
            //要考虑 switch 的情况
            if(this.vCfg.type!='switch' && !this.vInputValue){
                valid = -1;
                result = false;
            }
            else
                valid = 1 ;
        };

        if(! this.vCfg.mandatory && !this.vInputValue)
            valid = 0;

        switch(valid){
            case 1:
                this.renderStatus("remove",'invalid');
                this.renderStatus("add","valid");
                break;
            case -1:
                this.renderStatus("remove",'valid');
                this.renderStatus("add","invalid");
                break;
            case 0:
                this.renderStatus("remove",'valid');
                this.renderStatus("remove",'invalid');
                break;
        }
        return result;
    }

    getValue(){
        return this.vInputValue;
    }
}